package Day9;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author ：Yan Guang
 * @date ：Created in 2020/5/5 9:40
 * @description： 动态代理的举例
 */

interface Human {

    String getBelief();

    void eat(String food);
}

//被代理类
class SuperMan implements Human {

    @Override
    public String getBelief() {
        return "I believe I  fly";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    }
}

//        动态代理类
//        要想实现动态代理，需要解决的问题?
//        闷题一:如何根据加载到内存中的被代理类，动态的创建一个代理类及其对象。
//        问题二:当通过代理类的对象调用方法时，如何动态的去调用被代理类中的同名方法。
//class ProxyFactory {
//    //调用此方法，返回一个代理类的对象.解决问题一
//    public static Object getProxyInstance(Object obj) {//obj: 被代理类的对象
//        MyInvocationHandler handler = new MyInvocationHandler();
//
//        handler.bind(obj);
//
//        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
//    }
//
//    static class MyInvocationHandler implements InvocationHandler {
//
//        private Object obj;//需要使用被代理类的对象进行赋值
//        public void bind(Object obj){
//            this.obj=obj;
//        }
//        //当我们通过代理类的对象，调用方法a时， 就会自动的调用如下的方法: invoke()
//        //将被代理类要执行的方法a的功能就声明在invoke()中
//        @Override
//        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//            //此方法就是被代理类对象调用的方法
//            //obj:被代理类的对象
//            Object returnValue = method.invoke(obj, args);
//            //.上述方法的返回值就作为当前类中的invoke()的返回值。
//            return returnValue;
//        }
//    }
//}
        //再手打一遍
class ProxyFactory{
    public static Object getProxyInstance(Object obj){
        MyInvocationHandler handler = new MyInvocationHandler();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);

    }

    static class MyInvocationHandler implements InvocationHandler{
        private Object obj;

        public void bind(Object obj){
            this.obj=obj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object invoke = method.invoke(obj, args);
            return invoke;
        }
    }
}


public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        //当通过代理类对象调用方法时，会自动的调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣烫");
        //动态性,还可以放其他的不同的被代理对象
        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory . getProxyInstance(nikeClothFactory);
        proxyClothFactory.produceCloth();

    }
}
